package test.myorm.core;

import java.io.File;
import java.io.InputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import com.alibaba.druid.pool.DruidDataSource;

import test.myorm.chain.Interceptor;
import test.myorm.executor.Executor;

public class SqlSessionCreater {
	
	private String configPath;

	public SqlSessionCreater(String configPath) {
		super();
		this.configPath = configPath;
	}
	
	public SqlSession build() {
		Configuration configuration = new Configuration();
		SAXReader saxReader = new SAXReader();
		try {
			Document doc = saxReader.read(SqlSessionCreater.class.getResourceAsStream("/" + configPath + "/configuration.xml"));
			/*************************parse jdbc***************************/
			List jdbcList = doc.selectNodes("/configuration/jdbc");
			Element jdbcElement = (Element) jdbcList.get(0);
			String driver = jdbcElement.element("driver").getText();
			String url = jdbcElement.element("url").getText();
			String username = jdbcElement.element("username").getText();
			String password = jdbcElement.element("password").getText();
			DruidDataSource dataSource = new DruidDataSource();
			dataSource.setDriverClassName(driver);
			dataSource.setUrl(url);
			dataSource.setUsername(username);
			dataSource.setPassword(password);
			configuration.setDataSource(dataSource);
			
			/**************************parse interceptor************************/
			List interceptorList = doc.selectNodes("/configuration/chain/interceptor");
			Iterator interceptorIter = interceptorList.iterator();
			while(interceptorIter.hasNext()) {
				Element interceptorElement = (Element)interceptorIter.next();
				String classPath = interceptorElement.attributeValue("class");
				try {
					Class clazz = Class.forName(classPath);
					Interceptor interceptor = (Interceptor) clazz.newInstance();
					configuration.addInterceptor(interceptor);
				} catch (ClassNotFoundException e) {
					throw new RuntimeException("拦截器[" + classPath + "]不存在!!!");
				} catch (Exception e) {
					throw new RuntimeException("拦截器[" + classPath + "]实例化报错!!!");
				}
			}
			
			/**************************parse mapper*************************/
			List mappersList = doc.selectNodes("/configuration/mappers");
			Element mappersElement = (Element) mappersList.get(0);
			Element mapperXml = mappersElement.element("xml");
			if(mapperXml!=null) {
				List xmlList = mapperXml.elements("mapper");
				Iterator iter = xmlList.iterator();
				while(iter.hasNext()) {
					Element mapperElement = (Element)iter.next();
					String resource = mapperElement.attributeValue("resource");
					if(StringUtils.isNotBlank(resource)) {
						System.out.println("resource=" + resource);
						processMapper(configuration, saxReader, resource);
					}
					String directory = mapperElement.attributeValue("directory");
					if(StringUtils.isNotBlank(directory)) {
						System.out.println("directory=" + directory);
						String path = SqlSessionCreater.class.getResource(directory).getPath();
						System.out.println(path);
						File dir = new File(path);
						File[] files = dir.listFiles();
						for(File file : files) {
							String resourcePath = directory + "/" + file.getName();
							processMapper(configuration, saxReader, resourcePath);
						}
					}
				}
			}
			
			System.out.println(configuration);
			Executor executor = new Executor(configuration);
			SqlSession sqlSession = new SqlSession(configuration, executor);
			
			/***************************创建代理******************************/
			Element mapperClass = mappersElement.element("class");
			if(mapperClass!=null) {
				List classList = mapperClass.elements("mapper");
				Iterator iter = classList.iterator();
				while(iter.hasNext()) {
					Element mapperElement = (Element)iter.next();
					String classPath = mapperElement.attributeValue("class");
					if(StringUtils.isNotBlank(classPath)) {
						try {
							Class clazz = Class.forName(classPath);
							Object proxy = Proxy.newProxyInstance(clazz.getClassLoader(), new Class[] {clazz}, 
									new MapperProxy(configuration, clazz, sqlSession));
							configuration.addMapperProxy(classPath, proxy);
						} catch (ClassNotFoundException e) {
							throw new RuntimeException("不存在class[" + classPath + "]!!!");
						}
					}
					String packagePath = mapperElement.attributeValue("package");
					if(StringUtils.isNotBlank(packagePath)) {
						System.out.println("package=" + packagePath);
					}
				}
			}
			
			return sqlSession;
		} catch (DocumentException e) {
			throw new RuntimeException(e.getMessage());
		}
//		Executor executor = new Executor(configuration);
//		return new SqlSession(configuration, executor);
	}

	private void processMapper(Configuration configuration, SAXReader saxReader, String resource)
			throws DocumentException {
		System.out.println(resource);
		InputStream inputStream = SqlSessionCreater.class.getResourceAsStream(resource);
		Document xmlDoc = saxReader.read(inputStream);
		Element root = xmlDoc.getRootElement();
		String namespace = root.attributeValue("namespace");
		System.out.println("namespace=" + namespace);
		
		List resultMaps = root.elements("resultMap");
		Iterator mapIter = resultMaps.iterator();
		while(mapIter.hasNext()) {
			Element rmElement = (Element) mapIter.next();
			String id = rmElement.attributeValue("id");
			String classStr = rmElement.attributeValue("class");
			Class resultMapClass = null;
			try {
				resultMapClass = Class.forName(classStr);
			} catch (ClassNotFoundException e) {
				throw new RuntimeException("找不到对应resultMap[" + id + "]的class[" + classStr + "]!!!");
			}
			ResultMap resultMap = new ResultMap();
			resultMap.setClazz(resultMapClass);
			
			List propertys = rmElement.elements("property");
			Iterator propertyIter = propertys.iterator();
			while(propertyIter.hasNext()) {
				Element property = (Element) propertyIter.next();
				String name = property.attributeValue("name");
				String column = property.attributeValue("column");
//							String key = "resultMap." + id;
				resultMap.addColumnMapping(column, name);
			}
			configuration.addResultMap(namespace + "." + id, resultMap);
		}
		
		/*****************************sql******************************/
		List sqlList = root.selectNodes("select|insert|update|delete");
		Iterator sqlIter = sqlList.iterator();
		while(sqlIter.hasNext()) {
			Element sqlElement = (Element) sqlIter.next();
			String id = sqlElement.attributeValue("id");
			String parameterType = sqlElement.attributeValue("parameterType");
			String resultType = sqlElement.attributeValue("resultType");
			String resultMapId = sqlElement.attributeValue("resultMap");
			String sqlStr = sqlElement.getTextTrim();
			/************************处理paramterType**************************/
			List<String> paramList = getRegexStr(sqlStr, "#\\{([a-zA-Z]+)\\}");
			System.out.println("paramList=" + paramList);
			Parameter parameter = null;
			if(CollectionUtils.isNotEmpty(paramList)) {
				parameter = new Parameter();
				parameter.setType(Parameter.NAME);
				parameter.setSize(paramList.size());
				for(String param : paramList) {
					parameter.addKey(param);
				}
			} else {
				paramList = getRegexStr(sqlStr, "(\\?)");
				if(CollectionUtils.isNotEmpty(paramList)) {
					parameter = new Parameter();
					parameter.setType(Parameter.QUESMARK);
					parameter.setSize(paramList.size());
				}
				System.out.println("paramList=" + paramList);
			}
			if(parameter!=null) {
				Class parameterClass = Parameter.getShortResultType(parameterType);
				if(parameterClass==null) {
					try {
						parameterClass = Class.forName(parameterType);
					} catch (ClassNotFoundException e) {
						throw new RuntimeException("找不到对应parameterType[" + parameterType +"]");
					}
				}
				parameter.setClazz(parameterClass);
				System.out.println(parameter);	
			}
			
			/*************************处理resultMap*****************************/
			ResultMap resultMap = new ResultMap();
			resultMap.setClazz(HashMap.class);//默认为map
			if(StringUtils.isNotBlank(resultType)) {
				Class clazz = ResultMap.getShortResultType(resultType);
				if(clazz==null) {
					try {
						clazz = Class.forName(resultType);
					} catch (ClassNotFoundException e) {
						throw new RuntimeException("找不到对应resultType[" + resultType +"]");
					}
				}
				resultMap.setClazz(clazz);
			}
			if(StringUtils.isNotBlank(resultMapId)) {
				resultMap = configuration.getResultMap(namespace + "." + resultMapId);
			}
			
			/*******************************处理sql***********************************/
			if(StringUtils.isBlank(sqlStr)) {
				throw new RuntimeException("sql不能为空!!!");
			}
			sqlStr = sqlStr.replaceAll("#\\{([a-zA-Z]+)\\}", "?");
			
			String sqlType = sqlElement.getName();
			
			Sql sql = new Sql();
			sql.setParameter(parameter);
			if(sqlType.equals("select")) {
				sql.setType(Sql.SQL_SELECT);
			} else if(sqlType.equals("insert")) {
				sql.setType(Sql.SQL_INSERT);
			} else if(sqlType.equals("update")) {
				sql.setType(Sql.SQL_UPDATE);
			} else if(sqlType.equals("delete")) {
				sql.setType(Sql.SQL_DELETE);
			}
			if(sql.getType()==Sql.SQL_SELECT) {
				sql.setResultMap(resultMap);
			}
			sql.setSql(sqlStr);
			
			if("insert".equals(sqlType)) {
				String idTypeStr = sqlElement.attributeValue("idType");
				sql.setReturnIdType(Sql.ID_NONE);
				if(StringUtils.isNotBlank(idTypeStr)) {
					int idType = Integer.parseInt(idTypeStr);
					if(idType!=Sql.ID_GENERATE && idType!=Sql.ID_SELECT && idType!=Sql.ID_NONE) {
						throw new RuntimeException("不存在的idType[" + idType + "]");
					}
					sql.setReturnIdType(idType);
					if(idType==Sql.ID_SELECT) {
						Element element = sqlElement.element("idSql");
						if(element==null) {
							throw new RuntimeException("idType=1时，idSql不能为空!!!");
						}
						String idSql = element.getTextTrim();
						sql.setIdSql(idSql);
					}
					sql.setIdProperty(sqlElement.attributeValue("idProperty"));
				}
			}
			
//			sql.setIdProperty(idProperty);
//			sql.setIdSql(idSql);
//			sql.setReturnIdType(returnIdType);
			sql.setConfiguration(configuration);
			configuration.addSql(namespace + "." + id, sql);
			
			System.out.println("---------------sql--------------");
			System.out.println(sql);
			System.out.println("---------------sql--------------");
		}
		
		System.out.println("sqlKeys==>" + configuration.getSqlMap().keySet());
	}
	
	private List<String> getRegexStr(String str, String rgex){  
        List<String> list = new ArrayList<String>();  
        Pattern pattern = Pattern.compile(rgex);// 匹配的模式  
        Matcher m = pattern.matcher(str);  
        while (m.find()) {  
            list.add(m.group(1));
        }  
        return list;  
    }
	
	public static void main(String[] args) {
		new SqlSessionCreater("config").build();
	}

}
